/*!
 * \file module.h
 *
 * \brief 模块信息
 *
 * All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.\n
 * 模块信息
 *
 * \version 2.0
 * \author yaohl
 * \date 2014/09/29
 *
 */

#ifndef __MODULE_H_
#define __MODULE_H_

#include <pthread.h>

#include "frmem.h"
#include "frstr.h"
#include "frlist.h"
#include "frhash2.h"

#include "module_comm.h"
#include "conntrack.h"

/* L7层协议代号 */
#define APM_L7_UNKNOWN          0     /* 不明 */
#define APM_L7_SYNCMODULE       1     /* 同步模型 */
//#define APM_L7_ORACLE           10    /* oracle */
//#define APM_L7_MSSQL            11    /* mssql */
//#define APM_L7_HTTP             20    /* http */
//#define APM_L7_XML              21    /* xml */


/* L7层协议判断 */
#define APM_L7_IS_NO          0   /* 不是该协议 */
#define APM_L7_IS_YES         1   /* 是该协议 */
#define APM_L7_IS_UNKNOWN     2   /* 不能判断该协议 */
#define APM_L7_IS_DISABLE     3   /* 该协议禁止使用 */

#define APM_L7_ANALYZE_FAIL                 0x10           /* 0001 0000 解码失败 */
#define APM_L7_ANALYZE_REDETECT             0x20           /* 0010 0000 l7 协议重新判断 */
#define APM_L7_ANALYZE_TODO                 0x30           /* 0011 0000 解码还需要后续数据 */
#define APM_L7_ANALYZE_SUCC                 0x40           /* 0100 0000 解码成功 */
#define APM_L7_ANALYZE_STOP                 0x50           /* 0101 0000 解码结束 */

#define APM_L7_BIT_REQ                      0x01           /* request */
#define APM_L7_BIT_RESP                     0x02           /* response*/
#define APM_L7_BIT_LOGIN                    0x04           /* login */
#define APM_L7_BIT_LOGOUT                   0x08           /* logout */

#define APM_L7_ANALYZE_SET_REQ(x)           ( (x)|APM_L7_BIT_REQ )
#define APM_L7_ANALYZE_SET_RESP(x)          ( (x)|APM_L7_BIT_RESP )
#define APM_L7_ANALYZE_SET_LOGIN(x)         ( (x)|APM_L7_BIT_LOGIN )
#define APM_L7_ANALYZE_SET_LOGOUT(x)        ( (x)|APM_L7_BIT_LOGOUT )

#define APM_L7_ANALYZE_IS_REQ(x)            ( (x)&APM_L7_BIT_REQ )
#define APM_L7_ANALYZE_IS_RESP(x)           ( (x)&APM_L7_BIT_RESP )
#define APM_L7_ANALYZE_IS_LOGIN(x)          ( (x)&APM_L7_BIT_LOGIN )
#define APM_L7_ANALYZE_IS_LOGOUT(x)         ( (x)&APM_L7_BIT_LOGOUT )
#define APM_L7_ANALYZE_IS_SUCC(x)           ( ((x)&0xF0) == APM_L7_ANALYZE_SUCC )

/*! @brief 连接中l4和l7信息 */
typedef struct __st_trans_info {
    L4_transaction st_l4_trans;
    L7_transaction st_l7_trans;
} Frtrans_info;

/*! @brief login状态 */
typedef enum __em_login_status {
    FRLOGIN_UNKNOWN = 0,
    FRLOGIN_START = 1,
    FRLOGIN_SUCC,
    FRLOGIN_FAIL,
    FRLOGOUT_START,
    FRLOGOUT_END
} Frlogin_status;

#define FRLOGIN_STATUS_STR(x)           \
    (x==FRLOGIN_START?"login start":    \
            (x==FRLOGIN_SUCC?"login succ":      \
                (x==FRLOGIN_FAIL?"login fail":  \
                    (x==FRLOGOUT_START?"logout start":"logout"))))

/*! @brief 关联连接管理 */
typedef struct __st_exp_ref
{
    Frhash_header *p_hash_hdr;
    pthread_spinlock_t *p_splock;
} Frexp_ref;

/*! @brief 主机服务管理 */
typedef struct __st_service_ref
{
    Frhash_header *p_hash_hdr;
    pthread_spinlock_t *p_splock;
} Frservice_ref;

/*! @brief 协议模块进程内report信息共享 */
typedef struct __st_report_session_ref
{
    Frhash_header *p_hash_hdr_data;         //信息保存
    Frhash_header *p_hash_hdr_node_free;    //按协议保存释放内存函数,timeout时使用
    pthread_spinlock_t *p_splock;
} Frreport_session_ref;

/*! @brief 框架中的全局引用信息 */
typedef struct __st_apmContext
{
    Frexp_ref *p_st_exp_ref;            //关联连接信息
    Frexp_ref *p_st_exp2_ref;           //关联信息
    Frservice_ref *p_st_service_ref;    //主机服务管理
    Frreport_session_ref *p_st_report_session_ref;//report信息临时保留
    void *p_st_report_moduleRef;        //信息上报接口 Report_module
    void *p_st_mem_env;                 //内存相关信息 Frmem_env
    void *p_st_log_category;            //log句柄
} ApmContext;

/*! @brief 协议模块配置信息 */
typedef struct __st_l7_moduleconfig
{
    const char *p_l4_proto;     // 适用"tcp"/"udp"/"any"
    int i_l7_proto;             // 全局使用的l7代号，唯一，应申请后使用
    const char *p_module_name;  // 模块名称
    const char *p_version;      // 版本号
    int (*l7_detect)(Conntrack *p_st_conn, Apm_packet *p_st_packet); //判断协议
    int (*l7_analysis)(Conntrack *p_st_conn
                     , Apm_packet *p_st_packet
                     , Frhash_header  *p_st_hash_report   //保存Frreport_data
                       );      //L7层数据解码
    int (*session_destory)(void *p_session_private); //释放session_private数据
} L7_module_config;

/*!
* @brief L7_module是由C编写的最基本的L7分析模块，采用so方式动态加载\n
* 系统启动后每个模块应构造L7_module信息，调用register实现自注册
*/
struct __st_l7_module {
    char  *p_module_filenm;     /*!< 模块文件名 */
    char  *p_so_filenm;         /*!< 类库名称    */
    void  *p_so_handle;         /*!< 库函数加载句柄 */

    int i_l7_proto;             /*!< 全局使用的l7代号，唯一，应申请后使用 */
    u_short us_l4_proto;        /*!< 1 协议没有指定或识别时,指定tcp/udp有效; 6(IPPROTO_TCP)/17(IPPROTO_UDP)
                                   2 强行指定时没有该限制 */
    char *p_module_name;        /*!< 模块名称 */
    char *p_version;            /*!< 版本号 */

    /*!< 判断协议\n
     * \n
     * p_st_conn:   连接跟踪ct\n
     * p_st_data_in:入力数据\n
     * 返回值:APM_L7_IS_NO,APM_L7_IS_YES,APM_L7_IS_UNKNOWN */
    int (*l7_detect)(Conntrack *p_st_conn, Apm_packet *p_st_packet);

    /*!< L7层数据解码\n
     * \n
     * p_st_conn:        连接跟踪ct\n
     * p_st_data_in:     入力数据\n
     * p_st_hash_report: 解析后数据保存通过公用接口保存在结构体\n
     * p_st_list_output: 再次解析用数据\n
     * \n
     * 返回值: APM_L7_ANALYZE_FAIL,...,APM_L7_ANALYZE_DATA_REQ,APM_L7_ANALYZE_DATA_RESP */
    int (*l7_analysis)(Conntrack *p_st_conn
                    , Apm_packet *p_st_packet
                    , Frhash_header  *p_st_hash_report   //保存Frreport_data
                    );

    /*!< 释放session_private数据\n
     * \n
     * p_session_private:  解析解码过程中临时数据\n
     * 返回值:成功FR_SUCC, 失败FR_FAIL */
    int (*session_destory)(void *p_session_private);

    unsigned long ul_refcnt;        /*!< 引用次数 */
    long  l_del_tv_sec;             /*!< 发生删除动作的时间 sec */
};
//} L7_module;

/*!
* @brief L7_module_plugins
*    依附于L7_module之上的一组Plugin
*       主要用于进一步提取字段信息（如基于HTTP的session username）,采用Lua编写
*/
typedef struct __st_l7_module_plugin {
    int i_proto_depends; /*!< 依赖的module，采用l7_proto标识 */
    const char *p_plugin_name; /*!< plugin名 */
    int i_priority;     /*!< 调用优先级 */
    char *p_lua_src;    /*!< lua 代码 */
    char *p_lua_fun;    /*!< 调用lua的函数名 */

    //lua_State *p_lua;
} L7_module_plugin;

#endif
